package cp2013;

import java.text.ParseException;
import java.util.ArrayList;

import java.io.*;
import java.net.*;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;

/**
 *
 * @author AcerXPS
 */
public final class UserSystem {

    private ArrayList<Item> itemArr;
    private ArrayList<Item> itemSearched;
    private boolean connectionStatus;
    private int locker;
    private User user;
    private Socket sock;
    private InputStream input;
    private OutputStream output;
    private BufferedOutputStream writer;
    private BufferedInputStream reader;
    private ObjectOutputStream objectSender;
    private ObjectInputStream objectReader;
    private PrintWriter stringWriter;
    private BufferedReader stringReader;

    public UserSystem() {
        this.connectServer();
    }

    public void connectServer() {
        //connect to DB
        if (sock == null) {
            try {
                //create connection and streams
                sock = new Socket("127.0.0.1", 5000);

                input = sock.getInputStream();
                reader = new BufferedInputStream(input);
                reader.mark(0);
                stringReader = new BufferedReader(new InputStreamReader(input));

                output = sock.getOutputStream();
                writer = new BufferedOutputStream(output);
                stringWriter = new PrintWriter(output);
                objectSender = new ObjectOutputStream(writer);

                setConnectionStatus(true);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    public boolean register(String username, String password, String fName, String lName, String dob, String address, String eMail) throws IOException, InterruptedException {
        //send new user data to DB
        stringWriter.println("register");
        stringWriter.flush();
        stringWriter.println(username + ";" + password + ";" + fName + ";" + lName + ";" + dob + ";" + address + ";" + eMail);
        stringWriter.flush();

        do {
            if (stringReader.readLine().equalsIgnoreCase("success")) {
                return true;
            } else {
                return false;
            }
        } while (stringReader.readLine() == null);
    }

    public boolean login(String username, char[] pass) {
        //assign user from db
        user = null;

        stringWriter.println("login;" + username + ";" + String.valueOf(pass));
        stringWriter.flush();

        String login = "fail";
        
        try {
            login = stringReader.readLine();
        } catch (IOException ex) {
            Logger.getLogger(UserSystem.class.getName()).log(Level.SEVERE, null, ex);
        }
        if (!login.equalsIgnoreCase("fail")) {
                StringTokenizer st = new StringTokenizer(login, ";");
                String usernameFromServer = st.nextToken();
                int tokenFromServer = Integer.parseInt(st.nextToken());
                int userIDFromServer = Integer.parseInt(st.nextToken());
                user = new User(usernameFromServer, tokenFromServer, userIDFromServer);
                return true;
            } else {
                return false;
            }

    }

    public boolean placeItem(String iName, String desc, String finishDate, int startBid) throws IOException {
        stringWriter.println("place");
        stringWriter.flush();

        Item i = null;
        String sellerID = Integer.toString(this.getUser().getUserID());
        String sellerN = this.getUser().getUsername();
        Calendar currentDate = Calendar.getInstance();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
        String startDate = formatter.format(currentDate.getTime());
        String crrntBid = Integer.toString(0);
        String highBidder = "no bidder";

        i = new Item(iName,desc,sellerID,sellerN,startDate,finishDate,Integer.toString(startBid),crrntBid,highBidder);

        //send to DB
        objectSender.writeUnshared(i);
        objectSender.flush();
        objectSender.reset();


        do {
            if (stringReader.readLine().equalsIgnoreCase("success")) {
                return true;
            } else {
                return false;
            }
        } while (stringReader.readLine() == null);
    }



    public void search(String toSearch) {
        itemSearched = new ArrayList();
        for(int k =0; k < itemArr.size(); k++){
            if(itemArr.get(k).getItemName().equalsIgnoreCase(toSearch)){
                itemSearched.add(itemArr.get(k));
            }
        }
    }

    public void sort(int type) {
        switch(type){
            case 0:
                Collections.sort(itemArr, new nameCompare());
                break;
            case 1:
                Collections.sort(itemArr, new bidCompare());
                break;
            case 2:
                Collections.sort(itemArr, new dateCompare());
                break;
            default:
                //do nothing
        }
    }

    public boolean bid(int bidValue, int itemID) throws IOException {
        //send bid value to DB
        stringWriter.println("bid"+";"+itemID+";"+bidValue+";"+this.user.getUserID());
        stringWriter.flush();

        do {
            if (stringReader.readLine().equalsIgnoreCase("success")) {
                return true;
            } else {
                return false;
            }
        } while (stringReader.readLine() == null);
        
    }

    public boolean rechargeToken(int rechargeValue) throws IOException {
        stringWriter.println("recharge" + ";" + this.user.getUserID() + ";" + rechargeValue);
        stringWriter.flush();

        do {

            if (stringReader.readLine().equalsIgnoreCase("success")) {
                return true;
            } else {
                return false;
            }
        } while (stringReader.readLine() == null);

    }

    public void viewHistory() throws IOException {
        //query to DB
        JFrame frmHistory = new JFrame("Recharge History");
        JFrame frmTransaction = new JFrame("Transaction History");
        int limit = 0;
        
        stringWriter.println("view;"+this.getUser().getUserID());
        stringWriter.flush();


        limit = Integer.parseInt(stringReader.readLine());
        String[][] data = new String[limit][2];
        for(int i = 0; i<limit; i++){
            String strRow = stringReader.readLine();
            StringTokenizer st = new StringTokenizer(strRow, ";");
            data[i][0] = st.nextToken();
            data[i][1] = st.nextToken();
        }

        String rechargeColNames[] = {"Recharge Amount", "Date"};
        
        JTable tblRecharge = new JTable(data, rechargeColNames);
        tblRecharge.setEnabled(false);
        
        DefaultTableCellRenderer rechargeRenderer = new DefaultTableCellRenderer();
        rechargeRenderer.setHorizontalAlignment(JLabel.CENTER);
        tblRecharge.getColumnModel().getColumn(0).setCellRenderer(rechargeRenderer);
        tblRecharge.getColumnModel().getColumn(1).setCellRenderer(rechargeRenderer);
        
        JScrollPane rechargeScrollPane = new JScrollPane(tblRecharge);

        frmHistory.getContentPane().add(rechargeScrollPane);
        frmHistory.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frmHistory.setSize(400, 300);
        frmHistory.setVisible(true);
        
        limit = Integer.parseInt(stringReader.readLine());
        data = new String[limit][5];
        for(int i = 0; i<limit; i++){
            String strRow = stringReader.readLine();
            StringTokenizer st = new StringTokenizer(strRow, ";");
            data[i][0] = st.nextToken();
            data[i][1] = st.nextToken();
            data[i][2] = st.nextToken();
            data[i][3] = st.nextToken();
            data[i][4] = st.nextToken();
        }

        String transColNames[] = {"Date", "Item ID", "Item Name", "Token Used", "Seller Name"};
        JTable tblTrans = new JTable(data, transColNames);
        tblTrans.setEnabled(false);

        DefaultTableCellRenderer transRenderer = new DefaultTableCellRenderer();
        transRenderer.setHorizontalAlignment(JLabel.CENTER);
        tblTrans.getColumnModel().getColumn(0).setCellRenderer(transRenderer);
        tblTrans.getColumnModel().getColumn(1).setCellRenderer(transRenderer);
        tblTrans.getColumnModel().getColumn(2).setCellRenderer(transRenderer);
        
        JScrollPane transScrollPane = new JScrollPane(tblTrans);
        
        frmTransaction.getContentPane().add(transScrollPane);
        frmTransaction.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frmTransaction.setSize(700, 300);
        frmTransaction.setVisible(true);
    }

    public void logout() {
        this.user = null;
    }

    public boolean refresh() {
        final long TIMEOUT = 3000L;
        itemArr = new ArrayList();

        stringWriter.println("refresh");
        stringWriter.flush();

        
        Thread refreshThread = new Thread(new Refresh());
        refreshThread.start();
        synchronized (itemArr) {
            try {
                itemArr.wait(TIMEOUT);
            } catch (InterruptedException ex) {
                Logger.getLogger(UserSystem.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        if (itemArr.size() == locker) {
            return true;
        } else {
            return false;
        }
    }

    public ArrayList getItemArr() {
        return itemArr;
    }

    public ArrayList getItemSearched() {
        return itemSearched;
    }

    public User getUser() {
        return user;
    }

    /**
     * @return the connectionStatus
     */
    public boolean isConnectionStatus() {
        return connectionStatus;
    }

    /**
     * @param connectionStatus the connectionStatus to set
     */
    public void setConnectionStatus(boolean connectionStatus) {
        this.connectionStatus = connectionStatus;
    }
    
    public class Refresh implements Runnable{

        private int limit = -1;
        private Socket sock;
        private ObjectInputStream refReader;

        public Refresh(){
            try {
                sock = new Socket("127.0.0.1", 4848);
            } catch (UnknownHostException ex) {
                Logger.getLogger(UserSystem.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(UserSystem.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        public void run() {
        do {
            try {
                limit = Integer.parseInt(stringReader.readLine());
                locker = limit;
            } catch (IOException ex) {
                Logger.getLogger(UserSystem.class.getName()).log(Level.SEVERE, null, ex);
              
            }
        } while (limit == -1);
        
            try {
                if (refReader == null) {
                    refReader = new ObjectInputStream(sock.getInputStream());
                }
                while (itemArr.size() < limit) {
                    Item i = null;
                    i = (Item) refReader.readUnshared();
                    if (i != null) {
                        itemArr.add(i);
                    }
                }
                synchronized (itemArr) {
                    itemArr.notifyAll();
                    refReader.close();
                    sock.close();
                }


            } catch (IOException ex) {
                Logger.getLogger(UserSystem.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ClassNotFoundException ex) {
            }
        }
    }

    private class nameCompare implements Comparator<Item>{

        public int compare(Item i1, Item i2) {
            return i1.getItemName().compareTo(i2.getItemName());
        }

    }

    private class bidCompare implements Comparator<Item>{

        public int compare(Item i1, Item i2) {
            if(i1.getStartingBid() > i2.getStartingBid()){
                return 1;
            }else if(i1.getStartingBid() < i2.getStartingBid()){
                return -1;
            }else{
                return 0;
            }
        }
        
    }

    private class dateCompare implements Comparator<Item>{

        public int compare(Item i1, Item i2){
            SimpleDateFormat formatter = new SimpleDateFormat("dd MMMMM yyyy");
            Date date1 = null;
            Date date2 = null;
            try {
                date1 = formatter.parse(i1.getFinishDate());
                date2 = formatter.parse(i2.getFinishDate());
            } catch (ParseException ex) {
                Logger.getLogger(UserSystem.class.getName()).log(Level.SEVERE, null, ex);
            }

            if(date1.after(date2)){
                return 1;
            } else if (date1.before(date2)){
                return -1;
            } else{
                return 0;
            }
        }
    }
}// close MainUI
